#ifndef XPC_OS_H
#define XPC_OS_H

/******************************************************************************
 * os.h
 *------------------------------------------------------------------------*//**
 *
 * \file          os.h
 * \library       xpc
 * \author        Chris Ahlstrom
 * \updates       2008-03-06 to 2011-10-29
 * \version       $Revision$
 * \license       $XPC_SUITE_GPL_LICENSE$
 *
 *    Provides, it is hoped, all OS-specific feature macros.
 *
 *    This file defines symbols that depend on the operating system being
 *    used.   It tries to define only macros that do not need to be defined
 *    by the pre-build configuration scripts (except for user options that
 *    choose whether to build statically or not).
 *
 *    Also see the header files config.h or xpc-config.h (both are
 *    generated by ./configure), and the portable.h header file.  Most
 *    importantly, see the integers.h header file.
 *
 *    Here is a partial list of potential OS-defined C macros.  We don't see
 *    Cray, SGI, or ETA in the list.
 *
\verbatim
         __APPLE__
         __MACH__
         MACOSX
         __FreeBSD
         __OpenBSD
         __NetBSD
         _AIX
         _hpux
         __sun
         __SUN__
         mc68000
         sparc
         WIN32
         __CYGWIN__
         OS_LINUX (/usr/include/pci/config.h)
         POSIX
         __GNUC__  (C)
         __GNUCC__ (C++)
\endverbatim
 *
 * Ways of detecting the operating system:
 *
 *    -  "OSTYPE=linux-gnu" in the environment.  Might also find
 *       "HOSTTYPE=i686" in the environment.
 *    -  Determine the predefined macros by doing "touch foo.h ; cpp -dM
 *       foo.h".  Some of the following macros are defined when run on
 *       Linux:  __linux, __linux__, linux, __gnu_linux__, __unix,
 *       __unix__, unix, __i386, __i386__, i386, and __VERSION__.
 *
 * \bit64
 *    See the file 64-bits.txt in the doc directory of this project.
 *
 *//*-------------------------------------------------------------------------*/

#ifdef WIN32
#include "../w32/xpc-config.h"         /* defines all available HAVE macros   */
#ifdef _INCLUDE_XPC_C_XPC_CONFIG_H
#error Picking up UNIX version of xpc-config.h, check your solution settings.
#endif
#else
#include <xpc/xpc-config.h>            /* defines all available HAVE macros   */
#endif

 /*
  * These lines really screw up the compilation of the library, because of
  * a circular header file dependency, and the need for the size_t
  * declaration.  We put the macro call in version.h as a stop-gap
  * measure.
  *
  * #include "xpc/macros.h"
  * XPC_REVISION_DECL(os)
  */

/******************************************************************************
 * GNU_SOURCE
 *------------------------------------------------------------------------*//**
 *
 *    In "GNU C Library: System & Network Applications" (GNU Press), section
 *    1.3.4, a number of "feature macros" are presented.  Defining these
 *    macros causes certain functionality to be included in the code.
 *
\verbatim
      Defined  Symbol

               _POSIX_SOURCE
               _POSIX_C_SOURCE
               _BSD_SOURCE
        X      _SVID_SOURCE
        X      _XOPEN_SOURCE
        X      _XOPEN_SOURCE_EXTENDED
               _LARGEFILE_SOURCE
               _LARGEFILE64_SOURCE
               _FILE_OFFSET_BITS
        M      _ISOC99_SOURCE
        X      _GNU_SOURCE
        X      _REENTRANT
        X      _THREAD_SAFE
\endverbatim
 *
 *    X = defined below                <br>
 *    M = defined on gcc command line  <br>
 *    C = commented out by _XXX        <br>
 *
 *    If the macro _GNU_SOURCE is defined, pretty much everything is
 *    included.  GNU recommends defining this macro, so we do.
 *
 *    Some operating systems (or compilers) require other macros to be
 *    defined.  See below.
 *
 *//*-------------------------------------------------------------------------*/

#ifndef _GNU_SOURCE
#define _GNU_SOURCE              1
#endif

/******************************************************************************
 * GNU_SOURCE part 2
 *------------------------------------------------------------------------*//**
 *
 *    This macro defines an older style of GNU C, I think.
 *
 *    This definition is provisional.
 *
 *//*-------------------------------------------------------------------------*/

#ifdef __GNUC__
#if __GNUC < 3
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#endif
#endif

/******************************************************************************
 * XSI_STRERROR_R
 *------------------------------------------------------------------------*//**
 *
 *    This macro indicates that the XSI-compliant version of strerror_r()
 *    will be used.  See strerror(3) for details.
 *
 *    It is set to 'true' if the XSI-compliant version of strerror_r() is
 *    provided by GNU glibc.
 *
 *    The XSI-compliant version of strerror_r() is provided if:
 *
 *       (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
 *
 *    The XSI-compliant strerror_r() is preferred for portable applications.
 *    It returns the error string in the user-supplied buffer buf of length
 *    buflen.
 *
 *//*-------------------------------------------------------------------------*/

#ifndef XSI_STRERROR_R
#if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600
#if _GNU_SOURCE
#define XSI_STRERROR_R     0
#else
#define XSI_STRERROR_R     1
#endif
#endif
#endif

/******************************************************************************
 * unistd.h
 *------------------------------------------------------------------------*//**
 *
 *    This one is very common, and we might as well include it here.  Note
 *    that we cannot put this header file before the _GNU_SOURCE macro
 *    defined above.
 *
 *//*-------------------------------------------------------------------------*/

#if XPC_HAVE_UNISTD_H
#include <unistd.h>                    /* here, gives us _POSIX_VERSION       */
#endif

/******************************************************************************
 * Other concepts
 *-----------------------------------------------------------------------------
 *
 *    Items to consider.
 *
 *----------------------------------------------------------------------------*/

#ifndef	__PTH__

#ifndef	XPC_THREADSAFE
#define	XPC_THREADSAFE    1
#endif

#ifndef	POSIX_PTHREAD_SEMANTICS
#define	POSIX_PTHREAD_SEMANTICS
#endif

#endif

/******************************************************************************
 * DYNAMIC_LOCAL_ARRAYS
 *------------------------------------------------------------------------*//**
 *
 *    This macro defines a compiler feature we need to learn more about.
 *
 *//*-------------------------------------------------------------------------*/

#if __GNUC__ > 1 && ! defined __STRICT_ANSI__ && ! defined __PEDANTIC__
#define DYNAMIC_LOCAL_ARRAYS
#endif

/******************************************************************************
 * WIN32
 *------------------------------------------------------------------------*//**
 *
 *    We want to pepper our code with "WIN32", not "_WIN32".
 *
 *//*-------------------------------------------------------------------------*/

#ifdef _WIN32
#ifndef WIN32
#define WIN32
#endif
#endif

/******************************************************************************
 * POSIX
 *------------------------------------------------------------------------*//**
 *
 *    We want this macro defined in POSIX-style functions can be used.
 *
 *    In "GNU C Library: System & Network Applications" (GNU Press), section
 *    12.3, it is stated that the GNU C compiler predefines __POSIX__ if the
 *    target system is a POSIX system.
 *
 *    However, testing for __POSIX__ always fails, while testing for
 *    _POSIX_VERSION (a global variable under GNU, and a macro under UNIX,
 *    defined in unistd.h) and _POSIX_SOURCE do work.
 *
 *    Actually, using this macro is a bit coarse.  Linux and Cygwin (for
 *    example) provide a more fine-grained set of macros including the
 *    following (from /usr/include/sys/features.h in a Cygwin install):
 *
\verbatim
         _POSIX_JOB_CONTROL                     1
         _POSIX_SAVED_IDS                       0
         _POSIX_VERSION                      199009L
         _POSIX_THREADS                         1
         _POSIX_THREAD_PROCESS_SHARED           1
         _POSIX_THREAD_SAFE_FUNCTIONS           1
         _POSIX_THREAD_PRIORITY_SCHEDULING      1
         _POSIX_THREAD_ATTR_STACKSIZE           1
         _POSIX_SEMAPHORES                      1
         _POSIX_TIMERS                          1
\endverbatim
 *
 *    Cygwin is detectable via the macro __CYGWIN__ generated automatically
 *    by the configure script.  We do not need to explicitly define it.
 *    However, to enable the POSIX macro, we kludge it by defining
 *    _POSIX_SOURCE, even though this macro is not entirely appropriate for
 *    Cygwin.
 *
 *//*-------------------------------------------------------------------------*/

#ifdef _POSIX_VERSION
#ifndef POSIX
#define POSIX                    1
#endif
#ifdef WIN32
#error WIN32 and POSIX macros defined simultaneously
#endif
#endif

/******************************************************************************
 * XPC_OS_CATEGORY
 *------------------------------------------------------------------------*//**
 *
 *    This macros jumpstarts the process of determine the name of the OS on
 *    which this code executes.
 *
 *    See the documentation for the xpc_os_name() function.
 *
 *//*-------------------------------------------------------------------------*/

#ifdef POSIX
#define XPC_OS_CATEGORY     "POSIX"
#else
#ifdef WIN32
#define XPC_OS_CATEGORY     "Windows"
#else
#define XPC_OS_CATEGORY     "Other"
#endif
#endif

/******************************************************************************
 * 64-bit support
 *------------------------------------------------------------------------*//**
 *
 *    64-bit support is still a slightly unfamiliar concept.  The
 *    conventions for 64-bit support are not quite clear yet.  The following
 *    defines represent the first steps toward the POSIX C Wrapper library
 *    being 64-bit clean.
 *
 * \posix
 *    For POSIX, if the LP64 macro is defined (either by the compiler or the
 *    configure.ac file), set up XPC_64_BITS.
 *
 * \win64
 *    For Windows, if the _WIN64 macro is defined, set up LLP64, WIN64 and
 *    XPC_64_BITS.
 *
 *    Please note that, as per MSDN documentation, _WIN32 (and hence WIN32)
 *    is always defined, even when _WIN64 is defined.
 *
 * \todo
 *    Straighten all this out and consider having additional macros such as
 *    XPC_LLP64 (Win64) and XPC_LP64 (Lin64).
 *
 *    Also see integers.h, cpu.h, cpu.c, os.h, and os.c for more information.
 *
 *//*-------------------------------------------------------------------------*/

#ifndef XPC_64_BITS

#ifdef POSIX                        /* POSIX                                  */

#if LP64
#define XPC_64_BITS
#endif

#else                               /* Win32                                  */

#ifdef _WIN64
#define LLP64
#define WIN64
#define XPC_64_BITS
#endif

#endif                              /* POSIX/Win32                            */

#endif

/******************************************************************************
 * POSIX_SUCCESS
 *------------------------------------------------------------------------*//**
 *
 *    POSIX_SUCCESS is returned from a string function when it has processed
 *    a message that is not an error.
 *
 *    It is also a non-error value for most POSIX-conformant functions.
 *
 *    This macro defines the integer value returned by many POSIX functions
 *    when they succeed -- zero (0).
 *
 * \note
 *    Rather than testing this value directory, the macro functions
 *    is_posix_success() and not_posix_success() should be used.  See the
 *    descriptions of those macros for more information.
 *
 *//*-------------------------------------------------------------------------*/

#ifndef POSIX_SUCCESS
#define POSIX_SUCCESS              0
#endif

/******************************************************************************
 * POSIX_ERROR
 *------------------------------------------------------------------------*//**
 *
 *    POSIX_ERROR is returned from a string function when it has processed an
 *    error.
 *
 *    It indicates that an error is in force.  Normally, the caller
 *    then uses this indicator to set a class-based error message.
 *
 *    This macro defines the integer value returned by many POSIX functions
 *    when they fail -- minus one (-1).
 *
 *    The EXIT_FAILURE and POSIX_ERROR macros also have the same value.
 *
 * \note
 *    Rather than testing this value directory, the macro functions
 *    is_posix_error() and not_posix_error() should be used.  See the
 *    descriptions of those macros for more information.
 *
 *//*-------------------------------------------------------------------------*/

#ifndef POSIX_ERROR
#define POSIX_ERROR              (-1)
#endif

/******************************************************************************
 * is_posix_success()
 *------------------------------------------------------------------------*//**
 *
 *    This macro tests the integer value against POSIX_SUCCESS.
 *
 *    Other related macros are:
 *
 *       -  is_posix_success()
 *       -  is_posix_error()
 *       -  not_posix_success()
 *       -  not_posix_error()
 *       -  set_posix_success()
 *       -  set_posix_error()
 *
 * \note
 *    Some functions return values other than POSIX_ERROR when an error
 *    occurs.
 *
 *    Some functions return values other than POSIX_SUCCESS when the
 *    function succeeds.
 *
 *    Please refer to the online documentation for these quixotic functions,
 *    and decide which macro one want to use for the test, if any.
 *
 *    In some case, one might want to use a clearer test.  For example, the
 *    socket functions return a result that is POSIX_ERROR (-1) if the
 *    function fails, but non-zero integer values are returned if the
 *    function succeeds.  For these functions, the is_valid_socket() and
 *    not_valid_socket() macros are much more appropriate to use.
 *
 *//*-------------------------------------------------------------------------*/

#define is_posix_success(x)      ((x) == POSIX_SUCCESS)

/******************************************************************************
 * is_posix_error()
 *------------------------------------------------------------------------*//**
 *
 *    This macro tests the integer value against POSIX_ERROR (-1).
 *
 *//*-------------------------------------------------------------------------*/

#define is_posix_error(x)        ((x) == POSIX_ERROR)

/******************************************************************************
 * not_posix_success()
 *------------------------------------------------------------------------*//**
 *
 *    This macro tests the integer value against POSIX_SUCCESS (0).
 *
 *//*-------------------------------------------------------------------------*/

#define not_posix_success(x)     ((x) != POSIX_SUCCESS)

/******************************************************************************
 * not_posix_error()
 *------------------------------------------------------------------------*//**
 *
 *    This macro tests the integer value against POSIX_ERROR (-1).
 *
 *//*-------------------------------------------------------------------------*/

#define not_posix_error(x)       ((x) != POSIX_ERROR)

/******************************************************************************
 * set_posix_success()
 *------------------------------------------------------------------------*//**
 *
 *    This macro set the integer value to POSIX_SUCCESS (0).  The parameter
 *    must be an lvalue, as the assignment operator is used.
 *
 *//*-------------------------------------------------------------------------*/

#define set_posix_success(x)     ((x) = POSIX_SUCCESS)

/******************************************************************************
 * set_posix_error()
 *------------------------------------------------------------------------*//**
 *
 *    This macro set the integer value to POSIX_ERROR (-1).  The parameter
 *    must be an lvalue, as the assignment operator is used.
 *
 *//*-------------------------------------------------------------------------*/

#define set_posix_error(x)       ((x) = POSIX_ERROR)

/******************************************************************************
 * Mac OSX
 *------------------------------------------------------------------------*//**
 *
 *    Support for Mac OSX has not been tested or implemented in any way
 *    whatsoever, yet.
 *
 *//*-------------------------------------------------------------------------*/

#if defined __APPLE__ && defined __MACH__
#ifndef MACOSX
#define MACOSX
#define _P1003_1B_VISIBLE
#endif

/******************************************************************************
 * PTHREADS and NPTL_PTHREADS
 *------------------------------------------------------------------------*//**
 *
 *    Not used at this time.  Right now, the library requires pthread to be
 *    available, otherwise it will not build.
 *
 *    We're still not sure what is done with NPTL (Native POSIX Threading
 *    Library?)
 *
 *//*-------------------------------------------------------------------------*/

#ifndef PTHREADS
#define PTHREADS                 1
#define NPTL_PTHREADS            0
#endif
#endif

/******************************************************************************
 * __FreeBSD__ and __BSD_VISIBLE
 *------------------------------------------------------------------------*//**
 *
 *    Not sure quite how this works yet.
 *
 *//*-------------------------------------------------------------------------*/

#if defined __FreeBSD__
#ifndef __BSD_VISIBLE
#define __BSD_VISIBLE            1
#endif
#endif

/******************************************************************************
 * _AIX and _ALL_SOURCE
 *------------------------------------------------------------------------*//**
 *
 *    Not used.
 *
 *//*-------------------------------------------------------------------------*/

#ifdef _AIX
#ifndef _ALL_SOURCE
#define _ALL_SOURCE
#endif
#endif

/******************************************************************************
 * __hpux and _XOPEN_SOURCE_EXTENDED, etc
 *------------------------------------------------------------------------*//**
 *
 *    Not used.
 *
 *//*-------------------------------------------------------------------------*/

#ifdef  __hpux
#ifndef _XOPEN_SOURCE_EXTENDED
#define _XOPEN_SOURCE_EXTENDED
#endif

#ifndef _INCLUDE_LONGLONG
#define _INCLUDE_LONGLONG
#endif
#endif

/******************************************************************************
 * __sun, __SUN__, and __EXTENSIONS_
 *------------------------------------------------------------------------*//**
 *
 *    Not used.
 *
 *//*-------------------------------------------------------------------------*/

#if defined __sun || defined __SUN__
#define __EXTENSIONS__           1
#endif

/******************************************************************************
 * _REENTRANT and _THREAD_SAFE
 *------------------------------------------------------------------------*//**
 *
 *    Reentrancy is important.
 *
 *//*-------------------------------------------------------------------------*/

#ifndef _REENTRANT
#define _REENTRANT               1
#endif

/******************************************************************************
 * _THREAD_SAFE
 *------------------------------------------------------------------------*//**
 *
 *    Thread-safety is important.
 *
 *//*-------------------------------------------------------------------------*/

#ifndef _THREAD_SAFE
#define _THREAD_SAFE             1
#endif

/******************************************************************************
 * _XOPEN_SOURCE
 *------------------------------------------------------------------------*//**
 *
 *    In the GNU setup, this macro is already defined when _GNU_SOURCE is
 *    defined and <features.h> has already been included.
 *
 *//*-------------------------------------------------------------------------*/

#if ! defined _XOPEN_SOURCE && ! defined __FreeBSD__   \
   && ! defined __OpenBSD__ && ! defined __MACH__ && !defined __NetBSD__
#define _XOPEN_SOURCE          600
#endif

/******************************************************************************
 * XPC_PACKING and XPC_PACKED
 *------------------------------------------------------------------------*//**
 *
 *    Not used.
 *
 *//*-------------------------------------------------------------------------*/

#define XPC_PACKING

#if defined __GNUC__
#define XPC_PACKED
#elif ! defined __hpux && ! defined _AIX
#define XPC_PACKED
#endif

/*******************************************************************************
 * extern "C" support
 *-------------------------------------------------------------------------*//**
 *
 *    Place EXTERN_C_DEC before any external function declarations in the C
 *    modules, and place EXTERN_C_END after them.  These macros allow C++
 *    code to include those C header files without any extra typing.
 *
 *    Note that this sequence is duplicated in 'macros.h'.
 *
 *-----------------------------------------------------------------------------*/

#ifndef EXTERN_C_DEC

#ifdef __cplusplus
#define EXTERN_C_DEC   extern "C" {
#define EXTERN_C_END   }
#else
#define EXTERN_C_DEC
#define EXTERN_C_END
#endif

#endif

/******************************************************************************
 * External functions
 *-----------------------------------------------------------------------------
 *
 *    Provided by the C module.
 *
 *----------------------------------------------------------------------------*/

extern const char * xpc_os_name (void);
extern const char * xpc_host_name (void);
extern void xpc_the_sizeof_it (void);

#endif                                       /* XPC_OS_H                      */

/******************************************************************************
 * os.h
 *-----------------------------------------------------------------------------
 * Local Variables:
 * End:
 *-----------------------------------------------------------------------------
 * vim: ts=3 sw=3 et ft=c
 *----------------------------------------------------------------------------*/
